package com.tengits.amaplocation;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.util.Log;

import androidx.annotation.NonNull;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Promise;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.Arguments;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;

public class AMapLocationModule extends ReactContextBaseJavaModule implements LifecycleEventListener, AMapLocationListener{

    public static final String RECEIVER_LOCATION_ACTION = "com.tengits.location_in_background";

    private final ReactApplicationContext reactContext;
    private DeviceEventManagerModule.RCTDeviceEventEmitter eventEmitter;

    private AMapLocationClient locationClient;
    private boolean backRunning = false;
    private Promise mLocationPromise; // 保存Promise
  
    private BroadcastReceiver locationChangeBroadcastReceiver = new BroadcastReceiver() {
  
      @Override
      public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equals(RECEIVER_LOCATION_ACTION))
        {
          AMapLocation amapLocation = (AMapLocation)intent.getParcelableExtra("location");
          eventEmitter.emit("AMapGeolocation", toReadableMap(amapLocation, 2));
        }
      }
    };

    public AMapLocationModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
        
        this.reactContext.addLifecycleEventListener(this);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(RECEIVER_LOCATION_ACTION);
        this.reactContext.registerReceiver(locationChangeBroadcastReceiver, intentFilter);
    }

    @Override
    public String getName() {
        return "AMapLocation";
    }

    @Override
    public void onHostResume() {
        // Activity `onResume`
    }

    @Override
    public void onHostPause() {
        // Activity `onPause`
    }

    @Override
    public void onHostDestroy() {
        // Activity `onDestroy`
        reactContext.removeLifecycleEventListener(this);
        if (locationChangeBroadcastReceiver != null){
            reactContext.unregisterReceiver(locationChangeBroadcastReceiver);
            locationChangeBroadcastReceiver = null;
        }
        stopForegroundLocation();
        stopBackgroundLocation();
    }

    @ReactMethod
    public void initLocation(String key, Promise promise) {
        try{
            AMapLocationClient.setApiKey(key);
            if(locationClient != null) {
            locationClient.onDestroy();
            }
            eventEmitter = this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
            locationClient = new AMapLocationClient(this.reactContext);
            AMapLocationClientOption option = new AMapLocationClientOption();
            option.setOnceLocation(true);
            option.setNeedAddress(true);
            locationClient.setLocationOption(option);
            locationClient.setLocationListener(this);
        
            promise.resolve(1);
        }catch(Exception e) {
            promise.resolve(0);
        }
    }
    
    @ReactMethod
    public void startForegroundLocation(Promise promise) {
        this.mLocationPromise = promise;
        if (locationClient != null) {
            locationClient.startLocation();
            Log.e("AMapLocation", "startforegroundlocation");
        }
    }

    @ReactMethod
    public void stopForegroundLocation() {
        if (locationClient != null) {
            locationClient.stopLocation();
        }
    }

    @ReactMethod
    public void startBackgroundLocation() {
        Log.e("AMapLocation","startBackgroundLocation," + backRunning);
        if(backRunning) {
            return;
        }
        Intent grayIntent = new Intent(this.reactContext, LocationService.class);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            this.reactContext.startForegroundService(grayIntent);
        } else {
            this.reactContext.startService(grayIntent);
        }
        backRunning = true;
    }
    
    @ReactMethod
    public void stopBackgroundLocation() {
        Log.e("AMapLocation","stopBackgroundLocation," + backRunning);
        Intent grayIntent = new Intent(this.reactContext, LocationService.class);
        this.reactContext.stopService(grayIntent);
        backRunning = false;
    }

    @ReactMethod
    public void getLastLocation(Promise promise) {
        promise.resolve(toReadableMap(locationClient.getLastKnownLocation(), 1));
    }

    @ReactMethod
    public void isBackgroundLocation(Promise promise) {
        promise.resolve(backRunning);
    }

    @Override
    public void onLocationChanged(AMapLocation amapLocation) {
        if (amapLocation != null) {
            if (amapLocation.getErrorCode() == 0) {
                //Log.e("AMapLocation","receive");
                //eventEmitter.emit("AMapGeolocation", toReadableMap(amapLocation, 1));
                //可在其中解析amapLocation获取相应内容。
                invokeSuccessWithResult(toReadableMap(amapLocation, 1));
            }else {
            //定位失败时，可通过ErrCode（错误码）信息来确定失败的原因，errInfo是错误信息，详见错误码表。
            Log.e("AMapGeolocation","location Error, ErrCode:"
                + amapLocation.getErrorCode() + ", errInfo:"
                + amapLocation.getErrorInfo());
            }
            invokeError(amapLocation.getErrorCode(), amapLocation.getErrorInfo());
        }
    }

    private WritableMap toReadableMap(AMapLocation location, int type) {
        if (location != null) {
            WritableMap map = Arguments.createMap();
            map.putInt("type",type);
            map.putDouble("timestamp", location.getTime());
            map.putDouble("accuracy", location.getAccuracy());
            map.putDouble("latitude", location.getLatitude());
            map.putDouble("longitude", location.getLongitude());
            map.putDouble("altitude", location.getAltitude());
            map.putDouble("speed", location.getSpeed());
            if (!location.getAddress().isEmpty()) {
                map.putString("address", location.getAddress());
                map.putString("description", location.getDescription());
                map.putString("poiName", location.getPoiName());
                map.putString("country", location.getCountry());
                map.putString("province", location.getProvince());
                map.putString("city", location.getCity());
                map.putString("cityCode", location.getCityCode());
                map.putString("district", location.getDistrict());
                map.putString("street", location.getStreet());
                map.putString("streetNumber", location.getStreetNum());
                map.putString("adCode", location.getAdCode());
            }
            return map;
        }
        return null;
    }

    private void invokeSuccessWithResult(WritableMap location) {
        if (this.mLocationPromise != null) {
            this.mLocationPromise.resolve(location);
        }
    }

    /**
     * 取消选择时触发
     */
    private void invokeError(int resultCode, String message) {
        if (this.mLocationPromise != null) {
            this.mLocationPromise.reject(Integer.toString(resultCode), message);
        }
    }
}
